/*
 * Copyright 2004 original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.extremecomponents.table.view.freemarker;

import freemarker.cache.TemplateLoader;
import freemarker.cache.WebappTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.extremecomponents.table.core.TableModel;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.PageContext;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;


/**
 * Configuration Manager for the Freemarker's configuration
 *
 * @author Eccn-sshwsfc 
 */
public class DefaultFreemarkerManager implements FreemarkerManager {

    private static final Log log = LogFactory.getLog(FreemarkerManager.class);
    public static final String KEY_EXCEPTION = "exception";
    
    private freemarker.template.Configuration config;
    

    public DefaultFreemarkerManager() {
    	
	}

	public freemarker.template.Configuration getConfiguration(ServletContext servletContext, TableModel model) throws TemplateException {
        if (config == null) {
            config = createConfiguration(servletContext);
        }

        config.setWhitespaceStripping(true);

        return config;
    }

    public void populateModel(SimpleHash root, TableModel model) {

		Object context = model.getContext().getContextObject();
		if(PageContext.class.isAssignableFrom(context.getClass()))
		{
			HttpServletRequest request = (HttpServletRequest)((PageContext)context).getRequest();
				    	
	        // support for JSP exception pages, exposing the servlet or JSP exception
	        Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");

	        if (exception == null) {
	            exception = (Throwable) request.getAttribute("javax.servlet.error.JspException");
	        }

	        if (exception != null) {
	            root.put(KEY_EXCEPTION, exception);
	        }
		}
    }

    protected BeansWrapper getObjectWrapper() {
        return new DefaultObjectWrapper();
    }

    /**
     * The default template loader is a MultiTemplateLoader which includes
     * a ClassTemplateLoader and a WebappTemplateLoader (and a FileTemplateLoader depending on
     * the init-parameter 'TemplatePath').
     * <p/>
     * The ClassTemplateLoader will resolve fully qualified template includes
     * that begin with a slash. for example /com/company/template/common.ftl
     * <p/>
     * The WebappTemplateLoader attempts to resolve templates relative to the web root folder
     */
    protected TemplateLoader getTemplateLoader(ServletContext servletContext) {
    	return new WebappTemplateLoader(servletContext);
    	/*
    	List loaders = new ArrayList();    	
    	loaders.add(new WebappTemplateLoader(servletContext));
    	
    	if(ConfigManager.isSet(WaterConstants.WATER_FREEMARKER_LOADPATHS)){
    		loaderPaths = ConfigManager.get(WaterConstants.WATER_FREEMARKER_LOADPATHS);
    	}
    	
    	String[] loaderStrs = StringUtils.split(loaderPaths, WaterConstants.WATER_CONFIG_TOKEN);

        try {
	    	for(String loaderPath : loaderStrs){
	    		if(loaderPath.startsWith("classpath:")){
	    			loaderPath = loaderPath.substring("classpath:".length());	    			
	    			loaderPath = ClassLoaderUtil.getResource(loaderPath, getClass()).getFile();
	    		}
	    		loaders.add(new FileTemplateLoader(new File(loaderPath.trim())));
	    		
	    	}
        } catch (IOException e) {
            log.error("Invalid template path specified: " + e.getMessage(), e);
        }
        
        return new MultiTemplateLoader((TemplateLoader[])loaders.toArray());
         */
    }

    /**
     * Create the instance of the freemarker Configuration object.
     * <p/>
     * this implementation
     * <ul>
     * <li>obtains the default configuration from Configuration.getDefaultConfiguration()
     * <li>sets up template loading from a ClassTemplateLoader and a WebappTemplateLoader
     * <li>sets up the object wrapper to be the BeansWrapper
     * <li>loads settings from the classpath file /freemarker.properties
     * </ul>
     *
     * @param servletContext
     */
    protected freemarker.template.Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
        freemarker.template.Configuration configuration = new Configuration();

        configuration.setTemplateLoader(getTemplateLoader(servletContext));

        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);

        configuration.setObjectWrapper(getObjectWrapper());

        loadSettings(servletContext, configuration);

        return configuration;
    }

	/**
     * Load the settings from the /freemarker.properties file on the classpath
     *
     * @see freemarker.template.Configuration#setSettings for the definition of valid settings
     */
    protected void loadSettings(ServletContext servletContext, freemarker.template.Configuration configuration) {
        try {
            InputStream in = this.getClass().getResourceAsStream("freemarker.properties"); 

            if (in != null) {
                Properties p = new Properties();
                p.load(in);
                configuration.setSettings(p);
            }
        } catch (IOException e) {
            log.error("Error while loading freemarker settings from /freemarker.properties", e);
        } catch (TemplateException e) {
            log.error("Error while loading freemarker settings from /freemarker.properties", e);
        }
    }
}
